/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* globals Cmd, ColorSpace, Dict, Blob, Name, PDFJS, Ref, URL */

"use strict";

//MQZ. Oct.10.2012. Moved globalScope definition to lib/pdf.js
//var globalScope = (typeof window === 'undefined') ? this : window;

var isWorker = typeof window == "undefined";

var ERRORS = 0,
	WARNINGS = 1,
	INFOS = 5;
var verbosity = WARNINGS;

var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];

var TextRenderingMode = {
	FILL: 0,
	STROKE: 1,
	FILL_STROKE: 2,
	INVISIBLE: 3,
	FILL_ADD_TO_PATH: 4,
	STROKE_ADD_TO_PATH: 5,
	FILL_STROKE_ADD_TO_PATH: 6,
	ADD_TO_PATH: 7,
	FILL_STROKE_MASK: 3,
	ADD_TO_PATH_FLAG: 4,
};

// The global PDFJS object exposes the API
// In production, it will be declared outside a global wrapper
// In development, it will be declared here
if (!globalScope.PDFJS) {
	globalScope.PDFJS = {};
}

globalScope.PDFJS.pdfBug = false;

// All the possible operations for an operator list.
var OPS = (PDFJS.OPS = {
	// Intentionally start from 1 so it is easy to spot bad operators that will be
	// 0's.
	dependency: 1,
	setLineWidth: 2,
	setLineCap: 3,
	setLineJoin: 4,
	setMiterLimit: 5,
	setDash: 6,
	setRenderingIntent: 7,
	setFlatness: 8,
	setGState: 9,
	save: 10,
	restore: 11,
	transform: 12,
	moveTo: 13,
	lineTo: 14,
	curveTo: 15,
	curveTo2: 16,
	curveTo3: 17,
	closePath: 18,
	rectangle: 19,
	stroke: 20,
	closeStroke: 21,
	fill: 22,
	eoFill: 23,
	fillStroke: 24,
	eoFillStroke: 25,
	closeFillStroke: 26,
	closeEOFillStroke: 27,
	endPath: 28,
	clip: 29,
	eoClip: 30,
	beginText: 31,
	endText: 32,
	setCharSpacing: 33,
	setWordSpacing: 34,
	setHScale: 35,
	setLeading: 36,
	setFont: 37,
	setTextRenderingMode: 38,
	setTextRise: 39,
	moveText: 40,
	setLeadingMoveText: 41,
	setTextMatrix: 42,
	nextLine: 43,
	showText: 44,
	showSpacedText: 45,
	nextLineShowText: 46,
	nextLineSetSpacingShowText: 47,
	setCharWidth: 48,
	setCharWidthAndBounds: 49,
	setStrokeColorSpace: 50,
	setFillColorSpace: 51,
	setStrokeColor: 52,
	setStrokeColorN: 53,
	setFillColor: 54,
	setFillColorN: 55,
	setStrokeGray: 56,
	setFillGray: 57,
	setStrokeRGBColor: 58,
	setFillRGBColor: 59,
	setStrokeCMYKColor: 60,
	setFillCMYKColor: 61,
	shadingFill: 62,
	beginInlineImage: 63,
	beginImageData: 64,
	endInlineImage: 65,
	paintXObject: 66,
	markPoint: 67,
	markPointProps: 68,
	beginMarkedContent: 69,
	beginMarkedContentProps: 70,
	endMarkedContent: 71,
	beginCompat: 72,
	endCompat: 73,
	paintFormXObjectBegin: 74,
	paintFormXObjectEnd: 75,
	beginGroup: 76,
	endGroup: 77,
	beginAnnotations: 78,
	endAnnotations: 79,
	beginAnnotation: 80,
	endAnnotation: 81,
	paintJpegXObject: 82,
	paintImageMaskXObject: 83,
	paintImageMaskXObjectGroup: 84,
	paintImageXObject: 85,
	paintInlineImageXObject: 86,
	paintInlineImageXObjectGroup: 87,
});

//MQZ.Mar.22 Disabled Operators (to prevent image painting & annotation default appearance)
//paintJpegXObject, paintImageMaskXObject, paintImageMaskXObjectGroup, paintImageXObject, paintInlineImageXObject, paintInlineImageXObjectGroup
var NO_OPS = (PDFJS.NO_OPS = [82, 83, 84, 85, 86, 87]);
var NO_OPS_RANGE = (PDFJS.NO_OPS_RANGE = [78, 79, 80, 81]); //range pairs, all ops with each pair will be skipped. !important!

// Use only for debugging purposes. This should not be used in any code that is
// in mozilla master.
var log = (function () {
	var disableLogs = Boolean(Number(process?.env?.PDF2JSON_DISABLE_LOGS ?? "0"));

	if (
		!disableLogs &&
		"console" in globalScope &&
		"log" in globalScope["console"]
	) {
		return globalScope["console"]["log"].bind(globalScope["console"]);
	} else {
		return function nop() {};
	}
})();

// A notice for devs that will not trigger the fallback UI.  These are good
// for things that are helpful to devs, such as warning that Workers were
// disabled, which is important to devs but not end users.
function info(msg) {
	if (verbosity >= INFOS) {
		log("Info: " + msg);
		PDFJS.LogManager.notify("info", msg);
	}
}

// Non-fatal warnings that should trigger the fallback UI.
function warn(msg) {
	if (verbosity >= WARNINGS) {
		log("Warning: " + msg);
		PDFJS.LogManager.notify("warn", msg);
	}
}

// Fatal errors that should trigger the fallback UI and halt execution by
// throwing an exception.
function error(msg) {
	// If multiple arguments were passed, pass them all to the log function.
	if (arguments.length > 1) {
		var logArguments = ["Error:"];
		logArguments.push.apply(logArguments, arguments);
		log.apply(null, logArguments);
		// Join the arguments into a single string for the lines below.
		msg = [].join.call(arguments, " ");
	} else {
		//log('Error: ' + msg);
	}
	// log(backtrace());
	PDFJS.LogManager.notify('error', msg);
	throw new Error(msg);
}

// Missing features that should trigger the fallback UI.
function TODO(what) {
	warn("TODO: " + what);
}

function backtrace() {
	try {
		throw new Error();
	} catch (e) {
		return e.stack ? e.stack.split("\n").slice(2).join("\n") : "";
	}
}

function assert(cond, msg) {
	if (!cond) error(msg);
}

// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
// absolute URL, it will be returned as is.
function combineUrl(baseUrl, url) {
	if (!url) return baseUrl;
	if (url.indexOf(":") >= 0) return url;
	if (url.charAt(0) == "/") {
		// absolute path
		var i = baseUrl.indexOf("://");
		i = baseUrl.indexOf("/", i + 3);
		return baseUrl.substring(0, i) + url;
	} else {
		// relative path
		var pathLength = baseUrl.length,
			i;
		i = baseUrl.lastIndexOf("#");
		pathLength = i >= 0 ? i : pathLength;
		i = baseUrl.lastIndexOf("?", pathLength);
		pathLength = i >= 0 ? i : pathLength;
		var prefixLength = baseUrl.lastIndexOf("/", pathLength);
		return baseUrl.substring(0, prefixLength + 1) + url;
	}
}

// Validates if URL is safe and allowed, e.g. to avoid XSS.
function isValidUrl(url, allowRelative) {
	if (!url) {
		return false;
	}
	var colon = url.indexOf(":");
	if (colon < 0) {
		return allowRelative;
	}
	var protocol = url.substring(0, colon);
	switch (protocol) {
		case "http":
		case "https":
		case "ftp":
		case "mailto":
			return true;
		default:
			return false;
	}
}
PDFJS.isValidUrl = isValidUrl;

// In a well-formed PDF, |cond| holds.  If it doesn't, subsequent
// behavior is undefined.
function assertWellFormed(cond, msg) {
	if (!cond) error(msg);
}

var LogManager = (PDFJS.LogManager = (function LogManagerClosure() {
	var loggers = [];
	return {
		addLogger: function logManager_addLogger(logger) {
			loggers.push(logger);
		},
		notify: function (type, message) {
			for (var i = 0, ii = loggers.length; i < ii; i++) {
				var logger = loggers[i];
				if (logger[type]) logger[type](message);
			}
		},
	};
})());

function shadow(obj, prop, value) {
	Object.defineProperty(obj, prop, {
		value: value,
		enumerable: true,
		configurable: true,
		writable: false,
	});
	return value;
}

var PasswordResponses = (PDFJS.PasswordResponses = {
	NEED_PASSWORD: 1,
	INCORRECT_PASSWORD: 2,
});

var PasswordException = (function PasswordExceptionClosure() {
	function PasswordException(msg, code) {
		this.name = "PasswordException";
		this.message = msg;
		this.code = code;
	}

	PasswordException.prototype = new Error();
	PasswordException.constructor = PasswordException;

	return PasswordException;
})();

var UnknownErrorException = (function UnknownErrorExceptionClosure() {
	function UnknownErrorException(msg, details) {
		this.name = "UnknownErrorException";
		this.message = msg;
		this.details = details;
	}

	UnknownErrorException.prototype = new Error();
	UnknownErrorException.constructor = UnknownErrorException;

	return UnknownErrorException;
})();

var InvalidPDFException = (function InvalidPDFExceptionClosure() {
	function InvalidPDFException(msg) {
		this.name = "InvalidPDFException";
		this.message = msg;
	}

	InvalidPDFException.prototype = new Error();
	InvalidPDFException.constructor = InvalidPDFException;

	return InvalidPDFException;
})();

var MissingPDFException = (function MissingPDFExceptionClosure() {
	function MissingPDFException(msg) {
		this.name = "MissingPDFException";
		this.message = msg;
	}

	MissingPDFException.prototype = new Error();
	MissingPDFException.constructor = MissingPDFException;

	return MissingPDFException;
})();

var NotImplementedException = (function NotImplementedExceptionClosure() {
	function NotImplementedException(msg) {
		this.message = msg;
	}

	NotImplementedException.prototype = new Error();
	NotImplementedException.prototype.name = "NotImplementedException";
	NotImplementedException.constructor = NotImplementedException;

	return NotImplementedException;
})();

var MissingDataException = (function MissingDataExceptionClosure() {
	function MissingDataException(begin, end) {
		this.begin = begin;
		this.end = end;
		this.message = "Missing data [" + begin + ", " + end + ")";
	}

	MissingDataException.prototype = new Error();
	MissingDataException.prototype.name = "MissingDataException";
	MissingDataException.constructor = MissingDataException;

	return MissingDataException;
})();

var XRefParseException = (function XRefParseExceptionClosure() {
	function XRefParseException(msg) {
		this.message = msg;
	}

	XRefParseException.prototype = new Error();
	XRefParseException.prototype.name = "XRefParseException";
	XRefParseException.constructor = XRefParseException;

	return XRefParseException;
})();

function bytesToString(bytes) {
	var str = "";
	var length = bytes.length;
	for (var n = 0; n < length; ++n) str += String.fromCharCode(bytes[n]);
	return str;
}

function stringToBytes(str) {
	var length = str.length;
	var bytes = new Uint8Array(length);
	for (var n = 0; n < length; ++n) bytes[n] = str.charCodeAt(n) & 0xff;
	return bytes;
}

var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];

var Util = (PDFJS.Util = (function UtilClosure() {
	function Util() {}

	Util.makeCssRgb = function Util_makeCssRgb(rgb) {
		return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
	};

	Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
		var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
		return Util.makeCssRgb(rgb);
	};

	// Concatenates two transformation matrices together and returns the result.
	Util.transform = function Util_transform(m1, m2) {
		return [
			m1[0] * m2[0] + m1[2] * m2[1],
			m1[1] * m2[0] + m1[3] * m2[1],
			m1[0] * m2[2] + m1[2] * m2[3],
			m1[1] * m2[2] + m1[3] * m2[3],
			m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
			m1[1] * m2[4] + m1[3] * m2[5] + m1[5],
		];
	};

	// For 2d affine transforms
	Util.applyTransform = function Util_applyTransform(p, m) {
		var xt = p[0] * m[0] + p[1] * m[2] + m[4];
		var yt = p[0] * m[1] + p[1] * m[3] + m[5];
		return [xt, yt];
	};

	Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
		var d = m[0] * m[3] - m[1] * m[2];
		var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
		var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
		return [xt, yt];
	};

	// Applies the transform to the rectangle and finds the minimum axially
	// aligned bounding box.
	Util.getAxialAlignedBoundingBox = function Util_getAxialAlignedBoundingBox(
		r,
		m
	) {
		var p1 = Util.applyTransform(r, m);
		var p2 = Util.applyTransform(r.slice(2, 4), m);
		var p3 = Util.applyTransform([r[0], r[3]], m);
		var p4 = Util.applyTransform([r[2], r[1]], m);
		return [
			Math.min(p1[0], p2[0], p3[0], p4[0]),
			Math.min(p1[1], p2[1], p3[1], p4[1]),
			Math.max(p1[0], p2[0], p3[0], p4[0]),
			Math.max(p1[1], p2[1], p3[1], p4[1]),
		];
	};

	Util.inverseTransform = function Util_inverseTransform(m) {
		var d = m[0] * m[3] - m[1] * m[2];
		return [
			m[3] / d,
			-m[1] / d,
			-m[2] / d,
			m[0] / d,
			(m[2] * m[5] - m[4] * m[3]) / d,
			(m[4] * m[1] - m[5] * m[0]) / d,
		];
	};

	// Apply a generic 3d matrix M on a 3-vector v:
	//   | a b c |   | X |
	//   | d e f | x | Y |
	//   | g h i |   | Z |
	// M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
	// with v as [X,Y,Z]
	Util.apply3dTransform = function Util_apply3dTransform(m, v) {
		return [
			m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
			m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
			m[6] * v[0] + m[7] * v[1] + m[8] * v[2],
		];
	};

	// This calculation uses Singular Value Decomposition.
	// The SVD can be represented with formula A = USV. We are interested in the
	// matrix S here because it represents the scale values.
	Util.singularValueDecompose2dScale =
		function Util_singularValueDecompose2dScale(m) {
			var transpose = [m[0], m[2], m[1], m[3]];

			// Multiply matrix m with its transpose.
			var a = m[0] * transpose[0] + m[1] * transpose[2];
			var b = m[0] * transpose[1] + m[1] * transpose[3];
			var c = m[2] * transpose[0] + m[3] * transpose[2];
			var d = m[2] * transpose[1] + m[3] * transpose[3];

			// Solve the second degree polynomial to get roots.
			var first = (a + d) / 2;
			var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
			var sx = first + second || 1;
			var sy = first - second || 1;

			// Scale values are the square roots of the eigenvalues.
			return [Math.sqrt(sx), Math.sqrt(sy)];
		};

	// Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
	// For coordinate systems whose origin lies in the bottom-left, this
	// means normalization to (BL,TR) ordering. For systems with origin in the
	// top-left, this means (TL,BR) ordering.
	Util.normalizeRect = function Util_normalizeRect(rect) {
		var r = rect.slice(0); // clone rect
		if (rect[0] > rect[2]) {
			r[0] = rect[2];
			r[2] = rect[0];
		}
		if (rect[1] > rect[3]) {
			r[1] = rect[3];
			r[3] = rect[1];
		}
		return r;
	};

	// Returns a rectangle [x1, y1, x2, y2] corresponding to the
	// intersection of rect1 and rect2. If no intersection, returns 'null'
	// The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
	Util.intersect = function Util_intersect(rect1, rect2) {
		const xLow = Math.max(
			Math.min(rect1[0], rect1[2]),
			Math.min(rect2[0], rect2[2])
		);
		const xHigh = Math.min(
			Math.max(rect1[0], rect1[2]),
			Math.max(rect2[0], rect2[2])
		);
		if (xLow > xHigh) {
			return null;
		}
		const yLow = Math.max(
			Math.min(rect1[1], rect1[3]),
			Math.min(rect2[1], rect2[3])
		);
		const yHigh = Math.min(
			Math.max(rect1[1], rect1[3]),
			Math.max(rect2[1], rect2[3])
		);
		if (yLow > yHigh) {
			return null;
		}

		return [xLow, yLow, xHigh, yHigh];
	};

	Util.sign = function Util_sign(num) {
		return num < 0 ? -1 : 1;
	};

	// TODO(mack): Rename appendToArray
	Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
		Array.prototype.push.apply(arr1, arr2);
	};

	Util.prependToArray = function concatenateToArray(arr1, arr2) {
		Array.prototype.unshift.apply(arr1, arr2);
	};

	Util.extendObj = function extendObj(obj1, obj2) {
		for (var key in obj2) {
			obj1[key] = obj2[key];
		}
	};

	Util.getInheritableProperty = function Util_getInheritableProperty(
		dict,
		name
	) {
		while (dict && !dict.has(name)) {
			dict = dict.get("Parent");
		}
		if (!dict) {
			return null;
		}
		return dict.get(name);
	};

	Util.inherit = function Util_inherit(sub, base, prototype) {
		sub.prototype = Object.create(base.prototype);
		sub.prototype.constructor = sub;
		for (var prop in prototype) {
			sub.prototype[prop] = prototype[prop];
		}
	};

	Util.loadScript = function Util_loadScript(src, callback) {
		var script = document.createElement("script");
		var loaded = false;
		script.setAttribute("src", src);
		if (callback) {
			script.onload = function () {
				if (!loaded) {
					callback();
				}
				loaded = true;
			};
		}
		document.getElementsByTagName("head")[0].appendChild(script);
	};

	return Util;
})());

var PageViewport = (PDFJS.PageViewport = (function PageViewportClosure() {
	function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
		this.viewBox = viewBox;
		this.scale = scale;
		this.rotation = rotation;
		this.offsetX = offsetX;
		this.offsetY = offsetY;

		// creating transform to convert pdf coordinate system to the normal
		// canvas like coordinates taking in account scale and rotation
		var centerX = (viewBox[2] + viewBox[0]) / 2;
		var centerY = (viewBox[3] + viewBox[1]) / 2;
		var rotateA, rotateB, rotateC, rotateD;
		rotation = rotation % 360;
		rotation = rotation < 0 ? rotation + 360 : rotation;
		switch (rotation) {
			case 180:
				rotateA = -1;
				rotateB = 0;
				rotateC = 0;
				rotateD = 1;
				break;
			case 90:
				rotateA = 0;
				rotateB = 1;
				rotateC = 1;
				rotateD = 0;
				break;
			case 270:
				rotateA = 0;
				rotateB = -1;
				rotateC = -1;
				rotateD = 0;
				break;
			//case 0:
			default:
				rotateA = 1;
				rotateB = 0;
				rotateC = 0;
				rotateD = -1;
				break;
		}

		if (dontFlip) {
			rotateC = -rotateC;
			rotateD = -rotateD;
		}

		var offsetCanvasX, offsetCanvasY;
		var width, height;
		if (rotateA === 0) {
			offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
			offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
			width = Math.abs(viewBox[3] - viewBox[1]) * scale;
			height = Math.abs(viewBox[2] - viewBox[0]) * scale;
		} else {
			offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
			offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
			width = Math.abs(viewBox[2] - viewBox[0]) * scale;
			height = Math.abs(viewBox[3] - viewBox[1]) * scale;
		}
		// creating transform for the following operations:
		// translate(-centerX, -centerY), rotate and flip vertically,
		// scale, and translate(offsetCanvasX, offsetCanvasY)
		this.transform = [
			rotateA * scale,
			rotateB * scale,
			rotateC * scale,
			rotateD * scale,
			offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
			offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY,
		];

		this.width = width;
		this.height = height;
		this.fontScale = scale;
	}
	PageViewport.prototype = {
		clone: function PageViewPort_clone(args) {
			args = args || {};
			var scale = "scale" in args ? args.scale : this.scale;
			var rotation = "rotation" in args ? args.rotation : this.rotation;
			return new PageViewport(
				this.viewBox.slice(),
				scale,
				rotation,
				this.offsetX,
				this.offsetY,
				args.dontFlip
			);
		},
		convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
			return Util.applyTransform([x, y], this.transform);
		},
		convertToViewportRectangle:
			function PageViewport_convertToViewportRectangle(rect) {
				var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
				var br = Util.applyTransform([rect[2], rect[3]], this.transform);
				return [tl[0], tl[1], br[0], br[1]];
			},
		convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
			return Util.applyInverseTransform([x, y], this.transform);
		},
	};
	return PageViewport;
})());

var PDFStringTranslateTable = [
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8,
	0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192,
	0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018,
	0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d,
	0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac,
];

function stringToPDFString(str) {
	var i,
		n = str.length,
		str2 = "";
	if (str[0] === "\xFE" && str[1] === "\xFF") {
		// UTF16BE BOM
		for (i = 2; i < n; i += 2)
			str2 += String.fromCharCode(
				(str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)
			);
	} else {
		for (i = 0; i < n; ++i) {
			var code = PDFStringTranslateTable[str.charCodeAt(i)];
			str2 += code ? String.fromCharCode(code) : str.charAt(i);
		}
	}
	return str2;
}

function stringToUTF8String(str) {
	return decodeURIComponent(escape(str));
}

function isEmptyObj(obj) {
	for (var key in obj) {
		return false;
	}
	return true;
}

function isBool(v) {
	return typeof v == "boolean";
}

function isInt(v) {
	return typeof v == "number" && (v | 0) == v;
}

function isNum(v) {
	return typeof v == "number";
}

function isString(v) {
	return typeof v == "string";
}

function isNull(v) {
	return v === null;
}

function isName(v) {
	return v instanceof Name;
}

function isCmd(v, cmd) {
	return v instanceof Cmd && (!cmd || v.cmd == cmd);
}

function isDict(v, type) {
	if (!(v instanceof Dict)) {
		return false;
	}
	if (!type) {
		return true;
	}
	var dictType = v.get("Type");
	return isName(dictType) && dictType.name == type;
}

function isArray(v) {
	return v instanceof Array;
}

function isStream(v) {
	return (
		typeof v == "object" && v !== null && v !== undefined && "getBytes" in v
	);
}

function isArrayBuffer(v) {
	return (
		typeof v == "object" && v !== null && v !== undefined && "byteLength" in v
	);
}

function isRef(v) {
	return v instanceof Ref;
}

function isPDFFunction(v) {
	var fnDict;
	if (typeof v != "object") return false;
	else if (isDict(v)) fnDict = v;
	else if (isStream(v)) fnDict = v.dict;
	else return false;
	return fnDict.has("FunctionType");
}

/**
 * The following promise implementation tries to generally implment the
 * Promise/A+ spec. Some notable differences from other promise libaries are:
 * - There currently isn't a seperate deferred and promise object.
 * - Unhandled rejections eventually show an error if they aren't handled.
 *
 * Based off of the work in:
 * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
 */
var Promise = (PDFJS.Promise = (function PromiseClosure() {
	var STATUS_PENDING = 0;
	var STATUS_RESOLVED = 1;
	var STATUS_REJECTED = 2;

	// In an attempt to avoid silent exceptions, unhandled rejections are
	// tracked and if they aren't handled in a certain amount of time an
	// error is logged.
	var REJECTION_TIMEOUT = 500;

	var HandlerManager = {
		handlers: [],
		running: false,
		unhandledRejections: [],
		pendingRejectionCheck: false,

		scheduleHandlers: function scheduleHandlers(promise) {
			if (promise._status == STATUS_PENDING) {
				return;
			}

			this.handlers = this.handlers.concat(promise._handlers);
			promise._handlers = [];

			if (this.running) {
				return;
			}
			this.running = true;

			setTimeout(this.runHandlers.bind(this), 0);
		},

		runHandlers: function runHandlers() {
			while (this.handlers.length > 0) {
				var handler = this.handlers.shift();

				var nextStatus = handler.thisPromise._status;
				var nextValue = handler.thisPromise._value;

				try {
					if (nextStatus === STATUS_RESOLVED) {
						if (typeof handler.onResolve == "function") {
							nextValue = handler.onResolve(nextValue);
						}
					} else if (typeof handler.onReject === "function") {
						nextValue = handler.onReject(nextValue);
						nextStatus = STATUS_RESOLVED;

						if (handler.thisPromise._unhandledRejection) {
							this.removeUnhandeledRejection(handler.thisPromise);
						}
					}
				} catch (ex) {
					nextStatus = STATUS_REJECTED;
					nextValue = ex;
				}

				handler.nextPromise._updateStatus(nextStatus, nextValue);
			}

			this.running = false;
		},

		addUnhandledRejection: function addUnhandledRejection(promise) {
			this.unhandledRejections.push({
				promise: promise,
				time: Date.now(),
			});
			this.scheduleRejectionCheck();
		},

		removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
			promise._unhandledRejection = false;
			for (var i = 0; i < this.unhandledRejections.length; i++) {
				if (this.unhandledRejections[i].promise === promise) {
					this.unhandledRejections.splice(i);
					i--;
				}
			}
		},

		scheduleRejectionCheck: function scheduleRejectionCheck() {
			if (this.pendingRejectionCheck) {
				return;
			}
			this.pendingRejectionCheck = true;
			setTimeout(
				function rejectionCheck() {
					this.pendingRejectionCheck = false;
					var now = Date.now();
					for (var i = 0; i < this.unhandledRejections.length; i++) {
						if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
							var unhandled = this.unhandledRejections[i].promise._value;
							var msg = "Unhandled rejection: " + unhandled;
							if (unhandled.stack) {
								msg += "\n" + unhandled.stack;
							}
							warn(msg);
							this.unhandledRejections.splice(i);
							i--;
						}
					}
					if (this.unhandledRejections.length) {
						this.scheduleRejectionCheck();
					}
				}.bind(this),
				REJECTION_TIMEOUT
			);
		},
	};

	function Promise() {
		this._status = STATUS_PENDING;
		this._handlers = [];
	}
	/**
	 * Builds a promise that is resolved when all the passed in promises are
	 * resolved.
	 * @param {array} array of data and/or promises to wait for.
	 * @return {Promise} New dependant promise.
	 */
	Promise.all = function Promise_all(promises) {
		var deferred = new Promise();
		var unresolved = promises.length;
		var results = [];
		if (unresolved === 0) {
			deferred.resolve(results);
			return deferred;
		}
		function reject(reason) {
			if (deferred._status === STATUS_REJECTED) {
				return;
			}
			results = [];
			deferred.reject(reason);
		}
		for (var i = 0, ii = promises.length; i < ii; ++i) {
			var promise = promises[i];
			var resolve = (function (i) {
				return function (value) {
					if (deferred._status === STATUS_REJECTED) {
						return;
					}
					results[i] = value;
					unresolved--;
					if (unresolved === 0) deferred.resolve(results);
				};
			})(i);
			if (Promise.isPromise(promise)) {
				promise.then(resolve, reject);
			} else {
				resolve(promise);
			}
		}
		return deferred;
	};

	/**
	 * Checks if the value is likely a promise (has a 'then' function).
	 * @return {boolean} true if x is thenable
	 */
	Promise.isPromise = function Promise_isPromise(value) {
		return value && typeof value.then === "function";
	};

	Promise.prototype = {
		_status: null,
		_value: null,
		_handlers: null,
		_unhandledRejection: null,

		_updateStatus: function Promise__updateStatus(status, value) {
			if (
				this._status === STATUS_RESOLVED ||
				this._status === STATUS_REJECTED
			) {
				return;
			}

			if (status == STATUS_RESOLVED && Promise.isPromise(value)) {
				value.then(
					this._updateStatus.bind(this, STATUS_RESOLVED),
					this._updateStatus.bind(this, STATUS_REJECTED)
				);
				return;
			}

			this._status = status;
			this._value = value;

			if (status === STATUS_REJECTED && this._handlers.length === 0) {
				this._unhandledRejection = true;
				HandlerManager.addUnhandledRejection(this);
			}

			HandlerManager.scheduleHandlers(this);
		},

		get isResolved() {
			return this._status === STATUS_RESOLVED;
		},

		get isRejected() {
			return this._status === STATUS_REJECTED;
		},

		resolve: function Promise_resolve(value) {
			this._updateStatus(STATUS_RESOLVED, value);
		},

		reject: function Promise_reject(reason) {
			this._updateStatus(STATUS_REJECTED, reason);
		},

		then: function Promise_then(onResolve, onReject) {
			var nextPromise = new Promise();
			this._handlers.push({
				thisPromise: this,
				onResolve: onResolve,
				onReject: onReject,
				nextPromise: nextPromise,
			});
			HandlerManager.scheduleHandlers(this);
			return nextPromise;
		},
	};

	return Promise;
})());

var StatTimer = (function StatTimerClosure() {
	function rpad(str, pad, length) {
		while (str.length < length) str += pad;
		return str;
	}
	function StatTimer() {
		this.started = {};
		this.times = [];
		this.enabled = true;
	}
	StatTimer.prototype = {
		time: function StatTimer_time(name) {
			if (!this.enabled) return;
			if (name in this.started) warn("Timer is already running for " + name);
			this.started[name] = Date.now();
		},
		timeEnd: function StatTimer_timeEnd(name) {
			if (!this.enabled) return;
			if (!(name in this.started))
				warn("Timer has not been started for " + name);
			this.times.push({
				name: name,
				start: this.started[name],
				end: Date.now(),
			});
			// Remove timer from started so it can be called again.
			delete this.started[name];
		},
		toString: function StatTimer_toString() {
			var times = this.times;
			var out = "";
			// Find the longest name for padding purposes.
			var longest = 0;
			for (var i = 0, ii = times.length; i < ii; ++i) {
				var name = times[i]["name"];
				if (name.length > longest) longest = name.length;
			}
			for (var i = 0, ii = times.length; i < ii; ++i) {
				var span = times[i];
				var duration = span.end - span.start;
				out += rpad(span["name"], " ", longest) + " " + duration + "ms\n";
			}
			return out;
		},
	};
	return StatTimer;
})();

PDFJS.createBlob = function createBlob(data, contentType) {
	return new Blob([data], { type: contentType });
};

PDFJS.createObjectURL = (function createObjectURLClosure() {
	if (typeof URL !== "undefined" && URL.createObjectURL) {
		return function createObjectURL(data, contentType) {
			var blob = PDFJS.createBlob(data, contentType);
			return URL.createObjectURL(blob);
		};
	}

	// Blob/createObjectURL is not available, falling back to data schema.
	var digits =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

	return function createObjectURL(data, contentType) {
		var buffer = "data:" + contentType + ";base64,";
		for (var i = 0, ii = data.length; i < ii; i += 3) {
			var b1 = data[i] & 0xff;
			var b2 = data[i + 1] & 0xff;
			var b3 = data[i + 2] & 0xff;
			var d1 = b1 >> 2,
				d2 = ((b1 & 3) << 4) | (b2 >> 4);
			var d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64;
			var d4 = i + 2 < ii ? b3 & 0x3f : 64;
			buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
		}
		return buffer;
	};
})();

function MessageHandler(name, comObj) {
	this.name = name;
	this.comObj = comObj;
	this.callbackIndex = 1;
	this.postMessageTransfers = true;
	var callbacks = (this.callbacks = {});
	var ah = (this.actionHandler = {});

	ah["console_log"] = [
		function ahConsoleLog(data) {
			log.apply(null, data);
		},
	];
	// If there's no console available, console_error in the
	// action handler will do nothing.
	if ("console" in globalScope) {
		ah["console_error"] = [
			function ahConsoleError(data) {
				globalScope["console"].error.apply(null, data);
			},
		];
	} else {
		ah["console_error"] = [
			function ahConsoleError(data) {
				log.apply(null, data);
			},
		];
	}
	ah["_warn"] = [
		function ah_Warn(data) {
			warn(data);
		},
	];

	if (typeof comObj === "object") {
		comObj.onmessage = function messageHandlerComObjOnMessage(event) {
			var data = event.data;
			if (data.isReply) {
				var callbackId = data.callbackId;
				if (data.callbackId in callbacks) {
					var callback = callbacks[callbackId];
					delete callbacks[callbackId];
					callback(data.data);
				} else {
					error("Cannot resolve callback " + callbackId);
				}
			} else if (data.action in ah) {
				var action = ah[data.action];
				if (data.callbackId) {
					var promise = new Promise();
					promise.then(function (resolvedData) {
						comObj.postMessage({
							isReply: true,
							callbackId: data.callbackId,
							data: resolvedData,
						});
					});
					action[0].call(action[1], data.data, promise);
				} else {
					action[0].call(action[1], data.data);
				}
			} else {
				error("Unkown action from worker: " + data.action);
			}
		};
	}
}

MessageHandler.prototype = {
	on: function messageHandlerOn(actionName, handler, scope) {
		var ah = this.actionHandler;
		if (ah[actionName]) {
			error('There is already an actionName called "' + actionName + '"');
		}
		ah[actionName] = [handler, scope];
	},
	/**
	 * Sends a message to the comObj to invoke the action with the supplied data.
	 * @param {String} actionName Action to call.
	 * @param {JSON} data JSON data to send.
	 * @param {function} [callback] Optional callback that will handle a reply.
	 * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
	 */
	send: function messageHandlerSend(actionName, data, callback, transfers) {
		var message = {
			action: actionName,
			data: data,
		};
		if (callback) {
			var callbackId = this.callbackIndex++;
			this.callbacks[callbackId] = callback;
			message.callbackId = callbackId;
		}
		if (transfers && this.postMessageTransfers) {
			this.comObj.postMessage(message, transfers);
		} else {
			this.comObj.postMessage(message);
		}
	},
};

function loadJpegStream(id, imageUrl, objs) {
	var img = new Image();
	img.onload = function loadJpegStream_onloadClosure() {
		objs.resolve(id, img);
	};
	//  img.src = imageUrl;
	//MQZ. Apr.09.2013 calls windows.btoa safely
	img.src = "data:image/jpeg;base64," + img.btoa(imageUrl);
}

// MQZ Sep.14.2025 expose util methods without coupling to node:util
PDFJS.log = log;
PDFJS.info = info;
PDFJS.warn = warn;
PDFJS.error = error;
PDFJS.verbosity = function (verbo) {
	if (isNaN(verbo)) {
		verbosity = WARNINGS;
	} else {
		if (verbo <= ERRORS) {
			verbosity = ERRORS;
		} else if (verbo >= INFOS) {
			verbosity = INFOS;
		} else {
			verbosity = verbo;
		}
	}
};
// Initialize default verbosity level
PDFJS.verbosity();
